package edu.mercer.medapps.documentbldr;

import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.google.common.base.Optional;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkArgument;

/**
 * Implementation of DocumentInformation.<p>
 * 
 * Provides 
 * <ul>
 * <li> word analysis information
 * <li> OS/system information
 * </ul> 
 *
 * @see DocumentInformation
 */

public class DocumentAnalyzer implements DocumentInformation

	 <Info <? extends Object>, 
	 
	  Document <DocumentProperties>, 
	  
	  Exception>
{
	private Optional< Document<DocumentProperties> > _doc = Optional.absent();

	/** Collection key constant for file modification date stamp */
	
	final static String FILE_MODIFIED = DocumentInformation.FEATURES
														   .MODIFIED
														   .text();

	/** Collection key constant for file size */
	
	final static String FILE_SIZE = DocumentInformation.FEATURES
													   .SIZE
													   .text();

	/** Collection key constant for file name */
	
	final static String FILE_NAME = Document.FEATURES
											.FILENAME
											.text();

	/* private constructor */
	
	private DocumentAnalyzer(final Document<DocumentProperties> docIn)
	{
		super();
		
		_doc = Optional.of(docIn);
		
	}//constructor
	

	/**
	 * @param docIn - Document &#60; DocumentProperties &#62;, not null
	 * 
	 * @return DocumentAnalyzer - instance of this
	 */
	
	public DocumentAnalyzer ofDocument(final Document<DocumentProperties> 
		docIn)
	{
		checkNotNull( docIn, "null detected docIn argument" );
	
		_doc = Optional.of(docIn);
		
		return this;
		
	}//method

	
	/**
	 * Factory for DocumentAnalyzer creation.<p>
	 * 
	 * @param docIn - Document &#60; DocumentProperties &#62;
	 * 
	 * @return DocumentAnalyzer - new instance
	 */
	
	public static DocumentAnalyzer factory(final Document<DocumentProperties> 
		docIn)
	{
		return new DocumentAnalyzer(docIn);
		
	}//method
	
	
	@Fulfills("DocumentInformation")
	public Info<Long> technical() throws IOException
	{		
		final Long fileAltered = Files.getLastModifiedTime( getPath() )
									  .toMillis();

		final Long fileSize = Files.size( getPath() );

		/* note chained update usage populates collection in Info */
		
		return new Info<Long>().update( FILE_MODIFIED, fileAltered )
							   .update( FILE_SIZE    , fileSize    );
		
	}//method

	
	@Fulfills("DocumentInformation")
	public Info<? extends Object> lexical() throws IOException 
	{
		final List<String> linesIn = Files.readAllLines( getPath(), 
				Charset.forName("UTF8") );
		
		final Iterator<String> linesIter = linesIn.iterator();
		
		Integer wordCount = 0;
	
		final Pattern wordPattern = Pattern.compile(QUALITIES.PATTERN
															 .toString());

		while( linesIter.hasNext() )
		{
			String lineIn = linesIter.next();

			Matcher wordMatch = wordPattern.matcher(lineIn);

			while( wordMatch.find() )
			{
				if( wordMatch.group(QUALITIES.GROUP
											 .toString()) != null )
				{
					wordCount++;

				}//if

			}//if

		}//while
				
		return new Info<Object>().update("line count", linesIn.size())
								 .update("word count", wordCount);
				
	}//method

	
	private Path getPath()
	{
		final String fileNameStr = _doc.get()
	 			   .properties()
	 			   .retrieve( FILE_NAME );

		checkArgument(fileNameStr.length() > 0, 
				"fail to retrieve non-empty file name property from document");

		final Path filePath = Paths.get( fileNameStr );

		checkNotNull(filePath, "null detected in path retreived");
		
		return filePath;
		
	}//method

	
}//class
